`timescale  1 ns/1 ps

module spi_slave_recv_core #
(
    parameter               DATA_W = 8
)
(
    input   wire                clk,
    input   wire                rst,

    /*
     * bit[2] : lsbfe;  1, MSB first; 0, LSB first
     *
     * bit[7]   bit[6]   bit[5]   bit[4]   bit[3]   bit[2]   bit[1]   bit[0]
                                                    lsbfe    cpol     cpha
     */
    input   wire [07:00]        config_reg,
    input   wire                sclk,
    input   wire                scs,
    input   wire                mosi,

    /*
     * 借用axi-stream总线，但由于没有FIFO，读数据的一方需要保持tready一直有效
     */
    input   wire                m_axi_tready,
    output  reg                 m_axi_tvalid,
    output  reg  [DATA_W-1:00]  m_axi_tdata
);

reg     [DATA_W-1:00]       recv_data;
reg     [03:00]             sclk_rise_cnt = 0;
reg     [03:00]             sclk_fall_cnt = 0;

reg    [1:0]                sclk_r;
wire                        sclk_rise;
wire                        sclk_fall;

reg                         sclk_fall_r0;
reg                         sclk_rise_r0;

assign          sclk_rise = sclk_r[1:0] == 2'b01;
assign          sclk_fall = sclk_r[1:0] == 2'b10;

always @ (posedge clk)
begin
    if(rst)
        sclk_r    <= 2'b00;
    else
        sclk_r    <= {sclk_r[0], sclk};
end

always @ (posedge clk)
begin
    if(rst)
    begin
        sclk_fall_r0 <= 0;
        sclk_rise_r0 <= 0;
    end
    else
    begin
        sclk_fall_r0 <= sclk_fall;
        sclk_rise_r0 <= sclk_rise;
    end
end


always @ (posedge clk)
begin
    if(rst)
        sclk_rise_cnt <= 0;
    if(scs == 0)
    begin
        if(sclk_rise)
            sclk_rise_cnt <= sclk_rise_cnt + 1'b1;
    end
    else
        sclk_rise_cnt <= 0;
end

always @ (posedge clk)
begin
    if(rst)
        sclk_fall_cnt <= 0;
    if(scs == 0)
    begin
        if(sclk_fall)
            sclk_fall_cnt <= sclk_fall_cnt + 1'b1;
    end
    else
        sclk_fall_cnt <= 0;
end

always @ (posedge clk)
begin
    case (config_reg)
    2'b00:
    begin
        if(sclk_rise)
            recv_data[7:0] <= {recv_data[6:0], mosi};             // 最先进来的数据在最高位
    end
    2'b01:
    begin
        if(sclk_fall)
            recv_data[7:0] <= {recv_data[6:0], mosi};             // 最先进来的数据在最高位
    end
    2'b10:
    begin
        if(sclk_fall)
            recv_data[7:0] <= {recv_data[6:0], mosi};             // 最先进来的数据在最高位
    end
    2'b11:
    begin
        if(sclk_rise)
            recv_data[7:0] <= {recv_data[6:0], mosi};             // 最先进来的数据在最高位
    end
    default:
    begin
        /*code*/
    end
    endcase
end

always @ (posedge clk)
begin
    if(rst)
    begin
        m_axi_tvalid <= 0;
        m_axi_tdata <= 0;
    end
    case (config_reg)
    2'b00:
    begin
        if( (sclk_rise_cnt % DATA_W == 0) & sclk_fall & ~scs)
        begin
            m_axi_tvalid <= 1;
            m_axi_tdata <= recv_data;
        end
        else
            m_axi_tvalid <= 0;
    end
    2'b01:
    begin
        if( (sclk_fall_cnt % DATA_W == 0) && sclk_fall_r0 & ~scs)
        begin
            m_axi_tvalid <= 1;
            m_axi_tdata <= recv_data;
        end
        else
            m_axi_tvalid <= 0;
    end
    2'b10:
    begin
        if( (sclk_fall_cnt % DATA_W == 0) && sclk_rise & ~scs)
        begin
            m_axi_tvalid <= 1;
            m_axi_tdata <= recv_data;
        end
        else
            m_axi_tvalid <= 0;
    end
    2'b11:
    begin
        if( (sclk_rise_cnt % DATA_W == 0) & sclk_rise_r0 & ~scs)
        begin
            m_axi_tvalid <= 1;
            m_axi_tdata <= recv_data;
        end
        else
            m_axi_tvalid <= 0;
    end
    /*code*/
    default:
    begin
        /*code*/
    end
    endcase
end

always @ (posedge clk)
begin
    if(m_axi_tvalid)
        $display("at %t spi slave receive data = 0x%h", $time, m_axi_tdata);
end
endmodule
